# -*- coding: utf-8 -*-
"""
Module Description: 跨服皇决之选工具类
Time : 2021/8/2 
Author : sxj
File : cross_fight_utils.py
"""

from pyshare.utils.time_utils import getCT, getCountdown, check_in_time_interval, addTimes, getDaysCountdown, \
    is_in_one_day
from pyshare.const.lang.tips_info import TipsInfo
from pyshare.const.enums.activity import ActivityStatus
from pyshare.framework.error_handle import CrossGameException
from pyshare.const.enums.cross_fight import StageHaveMatch, StageToStartTime, CrossFightStage, PrepareTime, AwardTime, \
    CrossFightHourRankStage, IsNpc
from pyshare.dal.repository_impl import CrossFightTimeActivityRepository, CrossFightRosterRoleRepository, \
    CrossFightServerRepository, CrossFightActivityRoleRepository
from pyshare.dal.gameconfig.game_env import get_config_env_set
from pyshare.utils.equipment_utils import equipment_data_dict_to_list, equipment_data_list_to_dict


class CrossFightUtils(object):
    """
    跨服皇决之选工具类
    """

    def __init__(self, fight_id, is_check_status=True):
        """

        :param fight_id:
        :param is_check_status: 是否校验活动状态(删除活动的时候不需要检验)
        """
        self.fight_id = fight_id
        self.fight_record = CrossFightTimeActivityRepository.get_by_fight_id(fight_id)
        if not self.fight_record:
            raise CrossGameException(TipsInfo.ActivityKeys.ActivityNotFound)
        if is_check_status:
            if self.fight_record.activity_status != ActivityStatus.Open:
                raise CrossGameException(TipsInfo.ActivityKeys.ActivityNotFound)

    def get_stage_id(self, cur_time=None):
        """
        获取当前所处阶段
        :param cur_time: 当前时间
        :return: 0:代表预热器, 100:代表领奖期(皇决之选整体活动结束后的领奖期)
        """
        # {'status: False, 'info': 错误信息}
        # {'status: True, 'StageId': 当前阶段}
        res_dict = dict()

        if not cur_time:
            cur_time = getCT()

        # 未处于活动区间内
        if (cur_time < self.fight_record.prepare_time) or (cur_time > self.fight_record.award_end_time):
            res_dict['status'] = False
            res_dict['info'] = TipsInfo.ActivityKeys.activityIsEnd
            return res_dict

        res_dict['status'] = True

        # 预热期
        if (cur_time >= self.fight_record.prepare_time) and (cur_time < self.fight_record.first_stage_start_time):
            res_dict['StageId'] = PrepareTime
            return res_dict

        # 判断所属阶段
        for stage_id, filed_name in StageToStartTime.items():
            start_time = getattr(self.fight_record, StageToStartTime[stage_id])
            if stage_id == CrossFightStage.Fourth:
                end_time = self.fight_record.four_stage_end_time
            else:
                end_time = getattr(self.fight_record, StageToStartTime[stage_id + 1])
            if (cur_time >= start_time) and (cur_time < end_time):
                res_dict['StageId'] = stage_id
                return res_dict

        # 领奖期
        res_dict['StageId'] = AwardTime
        return res_dict

    def get_role_match_group_id(self, stage_id, rid):
        """
        获取玩家当前阶段所处赛程和分组id
        :param stage_id: 阶段id
        :param rid:
        :return: match_id
        """
        # {'status': False, 'info': 错误信息}
        # {'status': True, 'MatchId': 赛程id, 'GroupId': 分组id}
        res_dict = dict()

        res_dict['status'] = False
        if stage_id not in StageHaveMatch.keys():
            res_dict['info'] = TipsInfo.GlobalKeys.paramError
            return res_dict

        roster_role = CrossFightRosterRoleRepository.get_by_fight_stage_rid(self.fight_id, stage_id, rid)
        if not roster_role:
            res_dict['info'] = TipsInfo.CrossFight.CrossFightNotActivityRoster
            return res_dict

        res_dict['status'] = True
        res_dict['MatchId'] = roster_role.match_id
        res_dict['GroupId'] = roster_role.group_id
        return res_dict

    def check_stage_award_time(self, stage_id):
        """
        检验当时是否在领奖期
        :param stage_id: 阶段
        :return:
        """
        # 每天活动时间
        time_range = self.fight_record.open_time
        t = map(lambda x: int(x), time_range[-1].split(':'))

        if stage_id == CrossFightStage.First:
            close_time = self.fight_record.second_stage_start_time
        elif stage_id == CrossFightStage.Second:
            close_time = self.fight_record.third_stage_start_time
        elif stage_id == CrossFightStage.Third:
            close_time = self.fight_record.four_stage_start_time
        elif stage_id == CrossFightStage.Fourth:
            close_time = self.fight_record.award_end_time
        else:
            close_time = self.fight_record.award_end_time
        close_time = addTimes(close_time, seconds=-1)
        open_time = close_time.replace(hour=t[0], minute=t[1], second=t[2])
        if not (open_time <= getCT() < close_time):
            return False
        return True

    def check_award_time(self, stage_id):
        """
        检验当前是否领奖期(各个阶段的领奖期 + 活动领奖期)
        :param stage_id: 阶段
        :return:
        """
        # 每天活动时间
        time_range = self.fight_record.open_time
        t = map(lambda x: int(x), time_range[-1].split(':'))

        if stage_id == CrossFightStage.First:
            close_time = self.fight_record.second_stage_start_time
        elif stage_id == CrossFightStage.Second:
            close_time = self.fight_record.third_stage_start_time
        elif stage_id == CrossFightStage.Third:
            close_time = self.fight_record.four_stage_start_time
        elif stage_id == CrossFightStage.Fourth:
            close_time = self.fight_record.award_end_time
        elif stage_id == AwardTime:
            # 领奖期直接返回
            return True
        else:
            raise CrossGameException(TipsInfo.CrossFight.CrossFightActivityHasEnd)
        close_time = addTimes(close_time, seconds=-1)
        open_time = close_time.replace(hour=t[0], minute=t[1], second=t[2])
        if not (open_time <= getCT() < close_time):
            raise CrossGameException(TipsInfo.CrossFight.CrossFightActivityHasEnd)

    def get_match_info(self, rid):
        """
        获取玩家当前赛程详细新
        :param rid: 玩家rid
        :return:
        """
        # 获取当前阶段
        stage_stat = self.get_stage_id()
        if stage_stat.get("status", False):
            stage_id = stage_stat.get("StageId")

            # 获取玩家赛程和赛组
            match_stat = self.get_role_match_group_id(stage_id, rid)
            if match_stat.get("status", False):
                match_id = match_stat.get("MatchId")
                group_id = match_stat.get("GroupId")
                return stage_id, match_id, group_id
        return 0, 0, 0

    def is_on_roster(self, rid):
        """
        判断玩家是否在名单中
        :param rid: 玩家rid
        :return:
        """
        # 获取当前阶段
        roster_role = CrossFightRosterRoleRepository.filter_by_fightid(self.fight_id, rid)
        if not roster_role:
            raise CrossGameException(TipsInfo.CrossFight.CrossFightNotActivityRoster)

    def get_hour_rank_stage(self, is_system=False, is_chat=False):
        """
        获取当前小时榜的阶段
        :param is_system: 是否系统获取(特殊处理)
        :param is_chat: 是否聊天界面获取
        :return:
        """
        # 小时榜阶段
        stage_id = 0
        ct = getCT()
        time_now = ct

        # 获取当前阶段
        stage_stat = self.get_stage_id()
        if not stage_stat.get("status"):
            return stage_id
        if stage_stat.get("StageId", 0) != CrossFightStage.Fourth:
            return stage_id
        # 获取每天活动时间区间
        start_hour, end_hour = self.fight_record.open_time
        t1 = map(lambda x: int(x), start_hour.split(':'))
        start_time = ct.replace(hour=t1[0], minute=t1[1], second=t1[2])
        t2 = map(lambda x: int(x), end_hour.split(':'))
        end_time = ct.replace(hour=t2[0], minute=t2[1], second=t2[2])
        time_range_list = get_config_env_set("CrossFightHourRankTimeList")
        # 第一个小时榜开始时间
        first_hour, _ = time_range_list[0]
        t3 = map(lambda x: int(x), first_hour.split(':'))
        first_hour_time = ct.replace(hour=t3[0], minute=t3[1], second=t3[2])
        if not is_chat:
            if time_now < start_time or time_now > end_time or time_now < first_hour_time:
                return stage_id
        else:
            if time_now < start_time or time_now < first_hour_time:
                return stage_id

        # 超过最后一场小时榜，特殊下发
        _, last_end_time = time_range_list[-1]
        t = map(lambda x: int(x), last_end_time.split(':'))
        last_end_time = ct.replace(hour=t[0], minute=t[1], second=t[2])
        if time_now > last_end_time:
            if is_system:
                # 系统结算，由于小时榜结算是上一个榜，因此+1处理
                return len(time_range_list) + 1
            return CrossFightHourRankStage.Last

        for time_range in time_range_list:
            hour_start_time, hour_end_time = time_range
            t1 = map(lambda x: int(x), hour_start_time.split(':'))
            t2 = map(lambda x: int(x), hour_start_time.split(':'))
            hour_start_time = ct.replace(hour=t1[0], minute=t1[1], second=t1[2])
            hour_end_time = ct.replace(hour=t2[0], minute=t2[1], second=t2[2])
            # 小时榜未开始
            if time_now < hour_start_time:
                return stage_id
            # 小时榜第一阶段
            if time_now < hour_end_time:
                stage_id += 1
                return stage_id
            stage_id += 1
        return min(len(time_range_list), stage_id)

    def get_hour_rank_all_stage(self):
        """
        获取小时榜阶段总数
        :return:
        """
        # 获取每天活动时间区间
        start_hour, end_hour = self.fight_record.open_time
        t1 = map(lambda x: int(x), start_hour.split(':'))
        t2 = map(lambda x: int(x), end_hour.split(':'))

        time_interval = get_config_env_set("CrossFightHourRankTimeList")
        max_stage = (t2[0] - t1[0]) / time_interval
        return max(0, max_stage)

    def get_award_match_list(self, is_check_award_time=False):
        """
        获取当前时间点共可以领取奖励的赛程列表
        :return:
        """
        match_id_list = []
        # 获取当前阶段
        stage_stat = self.get_stage_id()
        if stage_stat.get("status"):
            stage_id = stage_stat.get("StageId")
            if stage_id == PrepareTime:
                return match_id_list
            if stage_id == AwardTime:
                for k, v in StageHaveMatch.iteritems():
                    match_id_list.extend(v)
                return match_id_list
            if stage_id == CrossFightStage.First:
                if is_check_award_time:
                    # 判断是否在领奖期
                    if self.check_stage_award_time(stage_id):
                        match_id_list.extend(StageHaveMatch[CrossFightStage.First])
            elif stage_id == CrossFightStage.Second:
                match_id_list.extend(StageHaveMatch[CrossFightStage.First])
                if is_check_award_time:
                    # 判断是否在领奖期
                    if self.check_stage_award_time(stage_id):
                        match_id_list.extend(StageHaveMatch[CrossFightStage.Second])
            elif stage_id == CrossFightStage.Third:
                match_id_list.extend(StageHaveMatch[CrossFightStage.First])
                match_id_list.extend(StageHaveMatch[CrossFightStage.Second])
                if is_check_award_time:
                    # 判断是否在领奖期
                    if self.check_stage_award_time(stage_id):
                        match_id_list.extend(StageHaveMatch[CrossFightStage.Third])
            elif stage_id == CrossFightStage.Fourth:
                match_id_list.extend(StageHaveMatch[CrossFightStage.First])
                match_id_list.extend(StageHaveMatch[CrossFightStage.Second])
                match_id_list.extend(StageHaveMatch[CrossFightStage.Third])
                if is_check_award_time:
                    # 判断是否在领奖期
                    if self.check_stage_award_time(stage_id):
                        match_id_list.extend(StageHaveMatch[CrossFightStage.Fourth])
            return match_id_list
        return match_id_list

    def is_first_day_open(self):
        """
        判断当前时间是否是各个赛段的第一天且活动开放
        :return:
        """
        is_open = True
        time_now = getCT()
        # 获取每天活动时间区间
        start_hour, _ = self.fight_record.open_time
        t1 = map(lambda x: int(x), start_hour.split(':'))
        # 第一阶段
        if (is_in_one_day(self.fight_record.first_stage_start_time)) and (
                self.fight_record.first_stage_start_time.replace(hour=t1[0], minute=t1[1], second=t1[2]) > time_now):
            is_open = False
        elif (is_in_one_day(self.fight_record.second_stage_start_time)) and (
                self.fight_record.second_stage_start_time.replace(hour=t1[0], minute=t1[1], second=t1[2]) > time_now):
            is_open = False
        elif (is_in_one_day(self.fight_record.third_stage_start_time)) and (
                self.fight_record.third_stage_start_time.replace(hour=t1[0], minute=t1[1], second=t1[2]) > time_now):
            is_open = False
        elif (is_in_one_day(self.fight_record.four_stage_start_time)) and (
                self.fight_record.four_stage_start_time.replace(hour=t1[0], minute=t1[1], second=t1[2]) > time_now):
            is_open = False
        return is_open

    def get_hour_rank_day(self):
        """获取当前小时榜天数"""
        day = 0
        if self.fight_record.four_stage_start_time <= getCT() <= self.fight_record.four_stage_end_time:
            day = getDaysCountdown(getCT(), self.fight_record.four_stage_start_time) + 1
        return day

    def get_hour_rank_days_list(self):
        """获取小时榜所有天数"""
        return getDaysCountdown(self.fight_record.four_stage_end_time, self.fight_record.four_stage_start_time) + 1


def get_cur_fight_record():
    """
    获取本大区当前时间开启的皇决之选
    :return:
    """
    open_activity = CrossFightTimeActivityRepository.filter_open_activity()
    if not open_activity:
        return None
    activity_list = [activity for activity in open_activity]
    fight_record = sorted(activity_list, key=lambda t: t.created_time, reverse=True)[0]
    return fight_record


def get_remote_activity(fight_id):
    """
    获取远程服务的请求参数
    :return:
    """
    activity_data = {}
    if fight_id:
        activity_data["FightId"] = fight_id
    return activity_data


def get_cross_activity(rid):
    """
    获取进行中的活动
    :param String rid: 角色标识
    :return:
    """

    fight_id = None
    activity_id = None
    fight_record = None

    open_activity = CrossFightTimeActivityRepository.filter_open_activity()

    if open_activity:
        activity_list = [activity for activity in open_activity]
        fight_record = sorted(activity_list, key=lambda t: t.created_time, reverse=True)[0]
        # if server_id:

        fight_id = fight_record.fight_id
        activity_role = CrossFightActivityRoleRepository.get_by_fightid_rid(fight_id, rid)
        if activity_role:
            activity_id = activity_role.activity_id

    return fight_id, activity_id, fight_record


def get_on_going_fight(rid, server_id, check_daily_open_time=False):
    """
    获取进行中的活动
    :param String rid: 角色标识
    :param Int server_id: 区服id
    :param DateTime check_daily_open_time: 是否校验每日开启时间
    :return:
    """

    fight_id = ""
    activity_id = ""
    fight_record = None
    activity_role = None

    # 是否每日开启时间
    is_daily_open_time = None

    open_activity = CrossFightTimeActivityRepository.filter_open_activity()

    if open_activity:
        fight_record = sorted(open_activity, key=lambda t: t.created_time, reverse=True)[0]

        fight_server = CrossFightServerRepository.get_by_server_id(server_id)
        if fight_server and server_id not in fight_record.exclude_server_list:
            fight_id = fight_record.fight_id

        activity_role = CrossFightRosterRoleRepository.get_by_one_fightid_rid(fight_id, rid)
        if activity_role:
            activity_id = activity_role.activity_id

        if check_daily_open_time:
            if check_in_time_interval(*fight_record.open_time):
                is_daily_open_time = True
            else:
                is_daily_open_time = False

    resp_dict = dict()
    resp_dict["FightId"] = fight_id
    resp_dict["ActivityId"] = activity_id
    resp_dict["FightRecord"] = fight_record
    resp_dict["ActivityRole"] = activity_role
    resp_dict["IsDailyOpenTime"] = is_daily_open_time
    return resp_dict


def team_data_dict_to_list(team_data):
    """
    战队信息中装备信息字典转列表
    :param team_data: {"队伍id": [[大臣ID,战力,爵位,装备,命格觉醒,当前穿戴皮肤,守护]]}
           装备: [{},{}]
    :return:
    """
    for team_id, data_list in team_data.items():
        for i in range(len(data_list)):
            if len(data_list[i]) == 0:
                # 空大臣,列表为空,不处理
                continue
            equipment_list = data_list[i][3]
            new_equipment_list = list()
            for equipment_data in equipment_list:
                # 已经是列表
                if isinstance(equipment_data, list):
                    new_equipment = equipment_data
                else:
                    # 装备信息字典转为列表
                    new_equipment = equipment_data_dict_to_list(equipment_data)
                new_equipment_list.append(new_equipment)
            data_list[i][3] = new_equipment_list
        team_data[team_id] = data_list
    return team_data


def team_data_list_to_dict(team_data):
    """
    战队信息中装备信息列表转字典
    :param team_data: {"队伍id": [[大臣ID,战力,爵位,装备,命格觉醒,当前穿戴皮肤,守护]]}
           装备: [[],[]]
    :return:
    """
    for team_id, data_list in team_data.items():
        for i in range(len(data_list)):
            if len(data_list[i]) == 0:
                # 空大臣,列表为空,不处理
                continue
            equipment_list = data_list[i][3]
            new_equipment_list = list()
            for equipment_data in equipment_list:
                # 已经是字典
                if isinstance(equipment_data, dict):
                    new_equipment = equipment_data
                else:
                    # 装备信息字典转为列表
                    new_equipment = equipment_data_list_to_dict(equipment_data)
                new_equipment_list.append(new_equipment)
            data_list[i][3] = new_equipment_list
        team_data[team_id] = data_list
    return team_data


def report_content_dict_to_list(content):
    """
    战报content中装备信息由字典转为列表
    :param content: {"AtkTeamData": team_data, "DefTeamData": team_data"}
                    team_data: {"队伍id": [[大臣ID,战力,爵位,装备,命格觉醒,当前穿戴皮肤,守护]]}
    :return:
    """
    # 攻方信息
    atk_team_data = content.get('AtkTeamData', None)
    # 守方信息
    def_team_data = content.get('DefTeamData', None)

    # 获取防守方是否是NPC,若是NPC,无需处理防守战报[NPC一定为防守方],因为NPC数据里无装备信息
    is_npc = content['IsNpc']

    # 更改队伍信息里大臣装备信息格式为列表
    if atk_team_data and isinstance(atk_team_data, dict):
        new_atk_team_data = team_data_dict_to_list(atk_team_data)
        content['AtkTeamData'] = new_atk_team_data
    if def_team_data and isinstance(def_team_data, dict) and (is_npc == IsNpc.NotNpc):
        new_def_team_data = team_data_dict_to_list(def_team_data)
        content['DefTeamData'] = new_def_team_data
    return content


def report_content_list_to_dict(content):
    """
    战报content中装备信息由列表转为字典
    :param content: {"AtkTeamData": team_data, "DefTeamData": team_data"}
                    team_data: {"队伍id": [[大臣ID,战力,爵位,装备,命格觉醒,当前穿戴皮肤,守护]]}
    :return:
    """
    # 攻方信息
    atk_team_data = content.get('AtkTeamData', None)
    # 守方信息
    def_team_data = content.get('DefTeamData', None)

    # 获取防守方是否是NPC,若是NPC,无需处理防守战报[NPC一定为防守方],因为NPC数据里无装备信息
    is_npc = content['IsNpc']

    # 更改队伍信息里大臣装备信息格式为列表
    if atk_team_data and isinstance(atk_team_data, dict):
        new_atk_team_data = team_data_list_to_dict(atk_team_data)
        content['AtkTeamData'] = new_atk_team_data
    if def_team_data and isinstance(def_team_data, dict) and (is_npc == IsNpc.NotNpc):
        new_def_team_data = team_data_list_to_dict(def_team_data)
        content['DefTeamData'] = new_def_team_data
    return content


def affair_enemy_dict_to_list(enemy, is_npc):
    """
    事件表SelectEnemyDict字段内装备信息字典转列表
    :param enemy: {"档位": {"TeamData":{}}}
                  team_data: {"队伍id": [[大臣ID,战力,爵位,装备,命格觉醒,当前穿戴皮肤,守护]]}
    :param is_npc: 是否是NPC(若是NPC,无需处理,因为NPC数据里无装备信息)
    :return:
    """
    if is_npc == IsNpc.Npc:
        return enemy

    for gear in enemy.keys():
        # gear:档位
        team_data = enemy[gear].get('TeamData', None)
        if team_data and isinstance(team_data, dict):
            team_data = team_data_dict_to_list(team_data)
            enemy[gear]['TeamData'] = team_data
    return enemy


def affair_enemy_list_to_dict(enemy, is_npc):
    """
    事件表SelectEnemyDict字段内装备信息列表转字典
    :param enemy: {"档位": {"TeamData":{}}}
                  team_data: {"队伍id": [[大臣ID,战力,爵位,装备,命格觉醒,当前穿戴皮肤,守护]]}
    :param is_npc: 是否是NPC(若是NPC,无需处理,因为NPC数据里无装备信息)
    :return:
    """
    if is_npc == IsNpc.Npc:
        return enemy

    for gear in enemy.keys():
        # gear:档位
        team_data = enemy[gear].get('TeamData', None)
        if team_data and isinstance(team_data, dict):
            team_data = team_data_list_to_dict(team_data)
            enemy[gear]['TeamData'] = team_data
    return enemy
